package cn.tedu.tmall.passport.service.impl;

import cn.tedu.tmall.common.enumerator.ServiceCode;
import cn.tedu.tmall.common.ex.ServiceException;
import cn.tedu.tmall.common.pojo.authentication.CurrentPrincipal;
import cn.tedu.tmall.common.pojo.po.UserStatePO;
import cn.tedu.tmall.passport.dao.persist.cache.IUserCacheRepository;
import cn.tedu.tmall.passport.dao.persist.repository.IUserRepository;
import cn.tedu.tmall.passport.pojo.param.UserLoginInfoParam;
import cn.tedu.tmall.passport.pojo.vo.UserLoginInfoVo;
import cn.tedu.tmall.passport.pojo.vo.UserLoginResultVo;
import cn.tedu.tmall.passport.service.IUserService;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class UserServiceImpl implements IUserService {
    @Value("${tmall.jwt.secret-key}")
    private String secretKey;
    @Value("${tmall.jwt.duration-in-minute}")
    private Long durationInMinute;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private IUserRepository repository;
    @Autowired
    private IUserCacheRepository cacheRepository;
    @Override
    public UserLoginResultVo login(UserLoginInfoParam userLoginInfoParam,String remoteAddr,String userAgent) {
        //TODO 1.通过用户名判断该用户是否存在
        //TODO 2.通过该用户的enable判断是否为正常状态
        //TODO 3.判断密码是否正确
        UserLoginInfoVo loginInfoByUsername =
                repository.getLoginInfoByUsername(userLoginInfoParam.getUsername());
        if (loginInfoByUsername == null) {
            String message = "登陆失败，用户名或密码错误";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }
        if (loginInfoByUsername.getEnable() == 0) {
            String message = "登陆失败，该账号已被禁用";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED_DISABLED, message);
        }
        if (!passwordEncoder.matches(userLoginInfoParam.getPassword(), loginInfoByUsername.getPassword())) {
            String message = "登陆失败，用户名或密码错误";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED, message);
        }
        //TODO 4.处理登录日志相关
        //当事人
        CurrentPrincipal principal = new CurrentPrincipal();
        principal.setId(loginInfoByUsername.getId());
        principal.setUsername(loginInfoByUsername.getUsername());

        //权限
        List<GrantedAuthority> authorities = new ArrayList<>();
        List<String> permissionValues = loginInfoByUsername.getPermissionValue();
        for(String value : permissionValues){
            authorities.add(new SimpleGrantedAuthority(value));
        }

        //将用户状态数据存入缓存中
        String s = JSON.toJSONString(authorities);
        UserStatePO userStatePO = new UserStatePO();
        userStatePO.setEnable(loginInfoByUsername.getEnable());
        userStatePO.setAuthoritesToString(s);
        cacheRepository.saveUserState(loginInfoByUsername.getId(),userStatePO);

        // Authentication authentication = new UsernamePasswordAuthenticationToken(principal,null,authorities);
        // SecurityContext securityContext = SecurityContextHolder.getContext();
        // securityContext.setAuthentication(authentication);

        Map<String,Object> claims = new HashMap();
        claims.put("id",loginInfoByUsername.getId());
        claims.put("username",loginInfoByUsername.getUsername());
        claims.put("remoteAddr",remoteAddr);
        claims.put("userAgent",userAgent);
        //设置过期时间
        Date date = new Date(System.currentTimeMillis()+1L*durationInMinute*60*1000);
        String jwt = Jwts.builder()
                //Header
                .setHeaderParam("alg","HS256")
                .setHeaderParam("type","JWT")
                //Payload
                .setClaims(claims)
                .setExpiration(date)
                //Verify Signature
                .signWith(SignatureAlgorithm.HS256,secretKey)
                .compact();

        UserLoginResultVo resultVo = new UserLoginResultVo();
        resultVo.setId(loginInfoByUsername.getId());
        resultVo.setUsername(loginInfoByUsername.getUsername());
        resultVo.setToken(jwt);
        resultVo.setAvatar(loginInfoByUsername.getAvatar());
        resultVo.setAuthorities(permissionValues);
        return resultVo;
    }
}
